package org.KeyCrafter.cmd;

import org.KeyCrafter.server.session.ClientSession;

public class Command {
    // 命令名字
    String name;

    // 实现函数(命令处理函数)
    CommandProc m_proc;

    /**
     * 参数个数，用于校验命令请求格式是否正确
     *     1. 当arity小于0时，表示命令参数数目大于arity
     *     2. 当arity大于0时，表示命令参数必须是arity
     * 注意: 命令名称本身也算一个参数
     * 在Redis命令的上下文中，arity（参数数量）可以是正数或者负数。
     * 正数表示命令需要的确切参数数量，而负数则表示命令可以接受不定数量的参数。
     * 例如，SET命令的arity是2，表示它需要两个参数：一个键和一个值。
     * 如果arity是-2，那么表示命令需要至少两个参数，但也可以接受更多。
     * 这对于像MSET这样的命令很有用，MSET可以接受任意数量的键值对，但至少需要一个。
     */
    int arity;

    // 字符串表示的 FLAG，(为了良好可读性)
    String sflags;

    // 实际FlAG，命令的二进制标志，服务器启动时解析sflags字段生成
    int flags;

    // 指定那些参数是key
    // 第一个参数是key
    int firstkey;
    // 最后一个参数是key
    int lastkey;
    // 第一个参数和最后一个参数的步长
    int keystep;

    // 统计信息
    // microseconds 记录了命令执行耗费的总毫微秒数
    // calls 是命令被执行的总次数
    // microseconds/calls即可计算出该命令的平均处理时间
    long microseconds;
    long calls;

    // 调用命令处理函数
    public void proc(ClientSession c) {
        m_proc.exec(c);
    }

    public void setCommandProc(CommandProc proc) {
        this.m_proc = proc;
    }

    // 字段获取
    public int arity() {
        return arity;
    }

    public String name() {
        return name;
    }

    // 调用次数加 1
    public void callsIncrement() {
        this.calls++;
    }

    // 累计时间
    public void accumulateTime(long time) {
        microseconds += time;
    }

    // 总调用次数
    long calls() {
        return calls;
    }

    // 总时间
    long total() {
        return microseconds;
    }

    // flags
    public int flags() {
        return this.flags;
    }

    public Command(String name, CommandProc proc, int arity, String sflags, int flags, int firstkey, int lastkey, int keystep, long microseconds, long calls) {
        this.name = name;
        this.m_proc = proc;
        this.arity = arity;
        this.sflags = sflags;
        this.flags = flags;
        this.firstkey = firstkey;
        this.lastkey = lastkey;
        this.keystep = keystep;
        this.microseconds = microseconds;
        this.calls = calls;
    }

    public Command(String name, CommandProc m_proc, int arity, String sflags, int firstkey, int lastkey, int keystep) {
        this.name = name;
        this.m_proc = m_proc;
        this.arity = arity;
        this.sflags = sflags;
        this.firstkey = firstkey;
        this.lastkey = lastkey;
        this.keystep = keystep;
    }
}
